package org.codegen.service.impl;

import freemarker.template.Configuration;
import org.codegen.service.CodeGenerator;
import org.codegen.service.CodeGeneratorManager;
import org.codegen.util.*;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author Jly
 * @date 2019/11/4  20:18
 */
public class DAOImplGenerator extends CodeGeneratorManager implements CodeGenerator {

    public void genCode(String tableName) {
        String modelName = StringUtils.tableNameConvertUpperCamel(tableName);
        Configuration cfg = getFreemarkerConfiguration();
        String customMapping = "/";
        String modelNameUpperCamel = modelName;
        String modelNameLowerCase = modelName.toLowerCase();
        //保存路径改变
        String localDaoPath = PACKAGE_PATH_DAO_IMPL.replaceAll(Const.TABLE_LOWER_CASE, modelNameLowerCase);

        Map<String, Object> data = DataUtil.getDataMapInit(
                tableName, modelName, modelNameUpperCamel, modelNameLowerCase);
        try {

            List<String> daoMethodsList = getDaoMethods(getMapperJavaFilePath(tableName, modelName,
                    customMapping,
                    modelNameUpperCamel),
                    modelNameUpperCamel);
            data.put("daoMethodsList", daoMethodsList);

            // 创建 Dao 接口
            File daoFile = new File(TARGET_PROJECT_PATH + JAVA_PATH + localDaoPath + customMapping
                    + modelNameUpperCamel + "DAOImpl.java");
            // 查看父级目录是否存在, 不存在则创建
            if (!daoFile.getParentFile().exists()) {
                daoFile.getParentFile().mkdirs();
            }
            cfg.getTemplate("daoImpl.ftl").process(data, new FileWriter(daoFile));
            logger.info(modelNameUpperCamel + "DaoImpl.java 生成成功!");

        } catch (Exception e) {
            throw new RuntimeException("DaoImpl 生成失败!", e);
        }
    }

    private String getMapperJavaFilePath(String tableName, String modelName, String customMapping,
                                         String modelNameUpperCamel) {
        String path = TARGET_PROJECT_PATH + JAVA_PATH + genLocalPath(PACKAGE_PATH_MAPPER, modelName) + customMapping + modelNameUpperCamel
                + "DAO.java";
        return path;
    }

    /**
     * 从给定的Mapper及其中的方法，生成Service需要的方法
     *
     * @param mapperJavaFilePath
     * @return
     * @throws IOException
     */
    public static List<String> getDaoMethods(String mapperJavaFilePath, String modelName) throws IOException {
        List<String> serviceMethodsContentList = new ArrayList<String>();
        String methodPattern = "([^import|^package]).*;";
        List<String> contentList = FileUtil.readFile2List(mapperJavaFilePath);
        for (String content : contentList) {
            boolean match = Pattern.matches(methodPattern, content);
            if (match) {
                // 去掉前后的空格
                content = content.trim();
                // 去掉后面的";"
                content = content.substring(0, content.length() - 1);
                String methodType = MethodUtil.getMethodReturnType(content);
                String methodName = MethodUtil.getMethodName(content);
                List<String> methodParamTypeList = MethodUtil.getMethodParamTypeList(content);
                List<String> methodParanNameList = MethodUtil.getMethodParamNameList(content);
                String mapperName = StringUtils.toLowerCaseFirstOne(modelName) + "Dao";
                StringBuilder methodContent = new StringBuilder();
                methodContent.append(genComment(methodName, methodParamTypeList, methodParanNameList, methodType));
                methodContent.append(StringUtils.FOUR_SPACES).append("@Override\n");
                methodContent.append(StringUtils.FOUR_SPACES).append("public ").append(methodType).append(" ")
                        .append(methodName).append("(");
                int index = 0;
                for (String methodParamType : methodParamTypeList) {
                    methodContent.append(MethodUtil.getMethodParamType(methodName, methodParamType, modelName));
                    methodContent.append(" ").append(methodParanNameList.get(index));
                    if (index < methodParamTypeList.size() - 1) {
                        methodContent.append(", ");
                    }
                    index++;
                }
                methodContent.append(") ").append("{\n");
                methodContent.append(StringUtils.FOUR_SPACES).append(StringUtils.FOUR_SPACES);
                if (methodType.equals("int")) {
                    if (methodName.equals("insert")) {
                        methodContent.append("return this.getSqlSessionTemplate().insert(");
                        methodContent.append("\"").append(MAPPER_PACKAGE).append(".")
                                .append(modelName).append("DAO.insert").append("\", record);\n");
                    } else if (methodName.equals("insertSelective")) {
                        methodContent.append("return this.getSqlSessionTemplate().insert(");
                        methodContent.append("\"").append(MAPPER_PACKAGE).append(".")
                                .append(modelName).append("DAO.insertSelective").append("\", record);\n");
                    } else if (methodName.equals("updateByExampleSelective")) {
                        methodContent.append("Map map = new HashMap<>();\n")
                                .append(StringUtils.EIGHT_SPACES).append("map.put(\"record\" , record);\n")
                                .append(StringUtils.EIGHT_SPACES).append("map.put(\"example\" , example);\n")
                                .append(StringUtils.EIGHT_SPACES).append("return this.getSqlSessionTemplate().update(\"").append(MAPPER_PACKAGE).append(".")
                                .append(modelName).append("DAO.updateByExampleSelective").append("\", map);\n");
                    } else if (methodName.equals("deleteByExample")) {
                        methodContent.append("return this.getSqlSessionTemplate().delete(\"");
                        methodContent.append(MAPPER_PACKAGE).append(".").append(modelName).append("DAO.deleteByExample").append("\", example);\n");
                    } else if (methodName.equals("deleteByPrimaryKey")) {
                        methodContent.append("return this.getSqlSessionTemplate().delete(\"").append(MAPPER_PACKAGE).append(".")
                                .append(modelName).append("DAO.deleteByPrimaryKey").append("\", " + methodParanNameList.get(0) + ");\n");
                    } else {
                        methodContent.append("return 0;\n");
                    }
                } else if (methodType.equals("long")) {
                    if (methodName.equals("countByExample")) {
                        methodContent.append("return this.getSqlSessionTemplate().selectOne(\"");
                        methodContent.append(MAPPER_PACKAGE).append(".").append(modelName).append("DAO.countByExample").append("\", example);\n");
                    } else {
                        methodContent.append("return 0L;\n");
                    }
                } else {
                    if (methodName.equals("selectByExample")) {
                        methodContent.append("return this.getSqlSessionTemplate().selectList(");
                        methodContent.append("\"").append(MAPPER_PACKAGE).append(".")
                                .append(modelName).append("DAO.selectByExample").append("\", example);\n");
                    } else if (methodName.equals("selectByPrimaryKey")) {
                        methodContent.append("return this.getSqlSessionTemplate().selectOne(\"").append(MAPPER_PACKAGE).append(".")
                                .append(modelName).append("DAO.selectByPrimaryKey").append("\", " + methodParanNameList.get(0) + ");\n");
                    } else if (methodName.equals("selectAll")) {
                        methodContent.append("return this.getSqlSessionTemplate().selectList(\"").append(MAPPER_PACKAGE).append(".")
                                .append(modelName).append("DAO.selectAll\");\n");
                    } else {
                        methodContent.append("return null;\n");
                    }
                }
//                methodContent.append("return ").append(mapperName).append("."
//                        + methodName).append("(").append(MethodUtil.listToString(methodParanNameList)).append(")").append(";\n");
                methodContent.append(StringUtils.FOUR_SPACES).append("}\n");
                serviceMethodsContentList.add(methodContent.toString());
            }
        }
        return serviceMethodsContentList;
    }
}
